import threading, platform
import whatap.agent.secure.security_master as secure
import whatap.agent.data.data_pack as data
from whatap.agent.counter.task_extrainfo import TaskExtraINFO
from whatap.agent.counter.task_base import TaskBase
from whatap.agent.counter.task_disk import TaskDisk
from whatap.agent.counter.task_network import TaskNet
from whatap.agent.counter.task_proc import TaskProc
from whatap.agent.counter.task_log import TaskLogEvent
from whatap.agent.counter.task_config import TaskConfig
from whatap.agent.counter.task_filesystem import TaskFileSystem
from whatap.agent.counter.task_tcp import TaskTCP
from whatap.util.date_util import DateUtil as dateutil
import whatap.util.logging_util as logging_util
import whatap.osinfo as osinfo
import whatap.agent.conf.configure as config
import whatap.pack.smbase_pack as smbase_pack
import time
from datetime import datetime, timedelta
import multiprocessing

module_loaded = datetime.now()
last_task_timestamp = 0
last_task_name = ""

class TimeoutException(Exception):
    pass

class HangException(Exception):
    pass


class TaskAction(threading.Thread):
    def __init__(self, task, name, lastActTime, timeout):
        threading.Thread.__init__(self)
        self.p = None
        self.os = None
        self.pcode = None
        self.oid = None
        self.now = None
        self.timeoutout = timeout
        self.done_event = threading.Event()
        self.hangCheck = False

        self.task  = task
        self.name = name
        self.lastActTime = lastActTime
        self.timeoutException = timeoutException

        if timeoutException:
            self.setDaemon(True)

    def set(self, os, pcode, oid, now):
        self.os = os
        self.pcode = pcode
        self.oid = oid
        self.now = now

    def run(self):
        while True:
            if not self.done_event.is_set():
                self.p = self.task.process(self.os, self.pcode, self.oid, self.now)
                self.done_event.set()

    def get(self):
        if not timeoutException:
            return self.task.process(self.os, self.pcode, self.oid, self.now)

        if self.hangCheck:
            if not self.done_event.is_set():
                raise HangtException("Hang Check Exception")
            
        self.done_event.clear()
        self.done_event.wait(timeout=self.timeout)

        if not self.done_event.is_set():
            self.hangCheck = True
            raise TimeoutException("Timeout Exception")
        else:
            self.hangCheck = False
            p = self.p
            self.p = None
            return p
        
        return None



class __CounterManager(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self, name='__CounterManager')
        self.setDaemon(True)

    def run(self):
        global last_task_timestamp

        tasks = []
        securetasks = []

        secu = secure.GetSecurityMaster()
        os = 0
        system = platform.system().lower()
        if system == "windows":
            os = smbase_pack.OS_WINDOW
        elif system == "linux":
            os = smbase_pack.OS_LINUX
        elif system == "darwin":
            os = smbase_pack.OS_OSX
        elif system == "sunos":
            os = smbase_pack.OS_SUNOS
        elif system == "aix":
            os = smbase_pack.OS_AIX
        elif system == "hp-ux":
            os = smbase_pack.OS_HPUX
        else:
            return

        task_timeout_except = config.GetConfig().task_timeout_except
        task_timeout = config.GetConfig.task_timeout

        if config.GetConfig().task_base:
            base = TaskAction(TaskBase(), "Base", 0, task_timeout)
            tasks.append(base)
            if task_timeout_except and task_timeout != 0:
                base.start()

        if config.GetConfig().task_disk:
            disk = TaskAction(TaskDisk(), "Disk", 0, task_timeout)
            tasks.append(disk)
            if task_timeout_except and task_timeout != 0:
                disk.start()

        if config.GetConfig().task_net:
            net = TaskAction(TaskNet(), "Net", 0, task_timeout)
            tasks.append(net)
            if task_timeout_except and task_timeout != 0:
                net.start()

        if config.GetConfig().task_proc:
            proc = TaskAction(TaskProc(), "Proc", 0, task_timeout)
            tasks.append(proc)
            if task_timeout_except and task_timeout != 0:
                proc.start()
            
        if config.GetConfig().task_config:
            con = TaskAction(TaskConfig(), "Config", 0, task_timeout)
            tasks.append(con)
            if task_timeout_except and task_timeout != 0:
                conn.start()

        if config.GetConfig().task_filesystem:
            filesystem = TaskAction(TaskFileSystem(), "Filesystem", 0, task_timeout)
            tasks.append(filesystem)
            if task_timeout_except and task_timeout != 0:
                filesystem.start()

        if config.GetConfig().task_tcpcheck:
            tcpcheck = TaskAction(TaskTCP(), "TCPCheck", 0)
            tasks.append(tcpcheck)
            if task_timeout_except and task_timeout != 0:
                tcpcheck.start()

        if config.GetConfig().task_logevent:
            logevent = TaskAction(TaskLogEvent(), "LogEvent", 0)
            securetasks.append(logevent)
            if task_timeout_except and task_timeout != 0:
                logevent.start()

        if config.GetConfig().task_osinfo:
            info = TaskAction(TaskExtraINFO(), "OSInfo", 0)
            securetasks.append(info)
            if task_timeout_except and task_timeout != 0:
                info.start()


        none_count = 0
        while True:
            try:
                time.sleep(0.5)
                now = osinfo.GetUptime()
                now_timestamp = dateutil.now()
                success_count = 0
                for each_task in tasks:
                    if each_task.task.interval() >= 5 and now >= each_task.lastActTime+each_task.task.interval() :
                        each_task.lastActTime = now
                        try:
                            p = None
                            logging_util.debug("[CounterManager] TaskStart : ", each_task.name)
                            last_task_name = each_task.name
                            if task_timeout_except:
                                p = run_with_timeout(each_task.task.process, 5, os, secu.pcode, secu.oid, now_timestamp)
                            else:
                                p = each_task.task.process(os, secu.pcode, secu.oid, now_timestamp)

                            if p :
                                logging_util.debug("[CounterManager] TaskSuccess : ", each_task.name)
                                data.SendHide(p)
                                last_task_timestamp = datetime.now()
                                success_count = success_count + 1
                        except TimeoutException, e:
                            logging_util.error("[CounterManager] Task : ", each_task.name, e)
                        except Exception, e:
                            logging_util.logStack(e)

                for each_task in securetasks:
                    if each_task.task.interval() >= 5 and now >= each_task.lastActTime + each_task.task.interval():
                        each_task.lastActTime = now
                        try:
                            p = None
                            logging_util.debug("[CounterManager] TaskStart : ", each_task.name)
                            last_task_name = each_task.name

                            if task_timeout_except:
                                p = run_with_timeout(each_task.task.process, 5, os, secu.pcode, secu.oid, now_timestamp)
                            else : 
                                p = each_task.task.process(os, secu.pcode, secu.oid, now_timestamp)

                            if p :
                                logging_util.debug("[CounterManager] TaskSuccess : ", each_task.name)
                                data.SendSecure(p)
                                last_task_timestamp = datetime.now()
                                success_count = success_count + 1
                        except TimeoutException, e:
                            logging_util.error("[CounterManager] Task : ", each_task.name, e)
                        except Exception, e:
                            logging_util.logStack(e)

                if success_count < 1:
                    if none_count > 10:
                        logging_util.error("[CounterManager] All Task None - count :", none_count)
                    none_count = none_count + 1
                else:
                    none_count = 0
            except Exception, e:
                logging_util.logStack(e)

            
counterManager =__CounterManager()

def startCounterManager():
    counterManager.start()

def isOK():
    global last_task_timestamp
    ret = True
    now = datetime.now()
    if now-module_loaded > timedelta(minutes = config.GetConfig().HealthCheckCoolTime):
        if last_task_timestamp and now-last_task_timestamp > timedelta(minutes = 1):
            ret = ret and False
            logging_util.error("[CounterManager] Health Check Fail - Last Task :  ", last_task_name)

    return ret
